﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Milan.Diagnostics;

namespace Milan.Deploy
{
	/// <summary>
	/// This class defines a package for install, test, update, uninstall, etc...
	/// Deploy.Package.CheckNewVersion()									// Running in main UI
	/// Deploy.Package.UploadNewVersion(string package.xml)					// Running in main UI or in service
	/// Deplay.Package.DownloadNewVersion()									// Running in a service or elevated process
	/// Deploy.Package.InstallNewVersion()									// Installs a new version if available -- must run elevated.
	/// 
	/// Several scenarios:  (1) Totally enclosed single program with no service
	/// HandleUpgrades(Package type)
	/// 
	/// </summary>
	public class Package
	{
		public Package()
		{
			Files = new List<File>();
			Links = new List<Link>();
			Servers = new List<string>();
		}
		public void AddFile(string sourceFile,string destination = null)
		{
			Files.Add(new File(sourceFile,destination));
		}
		public void AddFileWithLink(string file,string linkFile, string description)
		{
			Files.Add(new File(file));
			Links.Add(new Link(description,linkFile,"",file,"",file));
		}
		public static Package Load(string packageInfoXml)
		{
			Package package = null;
			try
			{
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(Package));
				TextReader textReader = new StreamReader(packageInfoXml);
				package = (Package)xmlSerializer.Deserialize(textReader);
				// Patch up the relative files and make them absolute
				foreach (var file in package.Files)
				{
					if (!Path.IsPathRooted(file.Source))
					{
						file.Source = Path.Combine( Path.GetDirectoryName(packageInfoXml), file.Source.Replace('/','\\') );
					}
					if (!System.IO.File.Exists(file.Source))
						log.Error("Source file is not found:" + file.Source);
				}
				textReader.Close();
			}
			catch (Exception)
			{
			}
			return package;
		}
		public class File
		{
			public File()
			{
				Destination = Source = null;
			}
			public File(string source, string destination = null)
			{
				Source = source;
				if (destination != null)
					Destination = destination;
				else
					Destination = source;
			}
			[XmlAttribute]
			public string Destination;
			[XmlAttribute]
			public string Source;
			public override string ToString()
			{
				return Destination + "=" + Source;
			}
		}
		public class Link
		{
			public Link()
			{
				Description = Shortcut = Target = IconLocation = CurrentDirectory = null;
			}
			public Link(string description, string shortcut, string currentDirectory, string target, string arguments, string iconLocation)
			{
				Description = description;
				Shortcut = shortcut;
				Target = target;
				IconLocation = iconLocation;
				CurrentDirectory = currentDirectory;
			}
			public string Description;
			public string Shortcut;
			public string Target;
			public string Arguments;
			public string IconLocation;
			public string CurrentDirectory;
			public int IconIndex;
			public override string ToString()
			{
				return Description + ";" + Shortcut + ";" + Target + ";" + Arguments + ";" + IconLocation + ";" + CurrentDirectory;
			}
		}
		public List<File> Files;
		public List<Link> Links;
		public string VersionFile;	// Which file in Files is the version file.
		public string Script;	// Uri script
		public List<string> Servers;// Server urls to base directory of deployment directory
		public string TestCommand;
		public string InstallCommand;
		public string UninstallCommand;
		/// <summary>
		/// Serializes this package object
		/// </summary>
		/// <param name="fileName">Where to save this object</param>
		public void Save( string fileName )
		{
			string fullFileName = System.IO.Path.GetFullPath(fileName);
			XmlSerializer serializer = new XmlSerializer(typeof(Package));
			TextWriter textWriter = new StreamWriter(fullFileName);
			serializer.Serialize(textWriter, this);
			textWriter.Close();
		}

		/// <summary>
		/// Performs an upload of this package if the version is newer than what is on the server.
		/// </summary>
		/// <returns>true if a newer version was uploaded.</returns>
		public bool UploadIfNew()
		{
			bool returns = false;

			if (Settings.CompanyMachine.GetValue("IsDevMachine") == "true")
			{
				Client client = new Client(this);
				for (int i = 0; i < client.UrlList.Length; ++i)
				{
					Version remoteVersion = client.GetLatestVersionInfo(client.UrlList[i]);
					if ((remoteVersion ?? (new Version(0, 0))) < Settings.ProductVersion)
					{
						try
						{
							if (client.UploadScriptUris[i] != null)
							{
								client.UploadEntireProductOnce(client.UploadScriptUris[i]);
								returns = true;
							}
						}
						catch (WebException)
						{
						}
					}
					++i;
				}
			}
			return returns;
		}
		public Version GetProductVersion()
		{
			Assembly assembly = Assembly.GetExecutingAssembly();
			FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
			return new Version(fvi.ProductVersion);
		}
	}
}
